from ctypes import byref, create_string_buffer, c_int, c_void_p, string_at, windll, WINFUNCTYPE, wintypes
import _queue, os, queue, threading
import config, tones
from .pcm import PcmPlayer
MSG_STOP = 10001
MSG_SPEAK = 10002
MSG_QUIT = 10003
PARAM_INPUT_TYPE = 1
selfDir = os.path.dirname(__file__)
binDir = os.path.join(selfDir, "bin")
dll = windll.LoadLibrary(os.path.join(binDir, 'ibmeci.dll'))
samples = 4096
user32 = windll.user32
returnDataNotProcessed, returnDataProcessed, returnDataAbort = range(3)
msgWaveformBuffer, msgPhonemeBuffer, msgIndexReply, msgPhonemeIndexReply, msgWordIndexReply = range(5)
vpGender, vpHeadSize, vpPitchBaseline, vpPitchFluctuation, vpRoughness, vpBreathiness, vpSpeed, vpVolume = range(8)
class Ibmeci:
    # 对 ibmeci.dll 封装的类
    callbacks = {}
    @WINFUNCTYPE(c_int, c_int, c_int, c_int, c_void_p)
    def callback (handle, msg, lpParam, data):
        # 处理回调函数
        return Ibmeci.callbacks[handle](msg, lpParam, data)
    def __init__(self):
        # 新建实例
        self.handle = dll.eciNew()
    def __del__(self):
        # 释放资源
        if not self.handle: return
        dll.eciDelete(self.handle)
        if self.handle in Ibmeci.callbacks.keys():
            del Ibmeci.callbacks[self.handle]
        self.handle = None
    def addText(self, text):
        # 追加文本
        dll.eciAddText(self.handle, text.encode('gbk', errors = 'ignore'))
    def stop(self):
        return dll.eciStop(self.handle)
    def synthesize(self):
        # 合成
        dll.eciSynthesize(self.handle)
    def synchronize(self):
        # 同步等待
        dll.eciSynchronize(self.handle)
    def speaking(self):
        # 判断是否在朗读
        return dll.eciSpeaking(self.handle)
    def getVoiceName(self, index):
        # 获取语音名称
        v=create_string_buffer(b'\0' * 255)
        dll.eciGetVoiceName(self.handle, index, byref(v))
        return v.value.decode('gbk')
    def copyVoice(self, voiceFrom, voiceTo):
        # 复制语音
        dll.eciCopyVoice(self.handle, voiceFrom, voiceTo)
    def registerCallback(self, callback, data):
        # 注册回调函数
        if callback:
            dll.eciRegisterCallback(self.handle, self.callback, data)
            Ibmeci.callbacks[self.handle] = callback
        else:
            dll.eciRegisterCallback(self.handle, None, data)
            if self.handle in Ibmeci.callbacks.keys():
                del Ibmeci.callbacks[self.handle]
    def setOutputBuffer(self, buffer):
        # 设置缓冲区
        dll.eciSetOutputBuffer(self.handle, samples, byref(buffer))
    def setParam(self, name, value):
        # 设置参数
        return dll.eciSetParam(self.handle, name, value)
    def setVoiceParam(self, key, value):
        # 设置语音参数
        dll.eciSetVoiceParam(self.handle, 0, key, value)
class EciSynthesizer:
    # Eci 合成器
    def run(self):
        # 运行在单独线程
        self.player = PcmPlayer(channels = 1, samplesPerSec = 11025, bitsPerSample = 16, wantDucking = False, outputDevice = config.conf["speech"]["outputDevice"])
        # 创建合成实例
        self.buffer = create_string_buffer(samples * 2)
        eci = Ibmeci()
        eci.registerCallback(self.callback, None)
        eci.setOutputBuffer(self.buffer)
        eci.setParam(PARAM_INPUT_TYPE, 1)
        # 线程消息循环
        msg = wintypes.MSG()
        while hasattr(self, 'thread'):
            user32.GetMessageA(byref(msg), 0, 0, 0)
            if msg.message == MSG_STOP:
                eci.stop()
            elif msg.message == MSG_SPEAK:
                self.handle(eci)
            elif msg.message == MSG_QUIT: break
            user32.TranslateMessage(byref(msg))
            user32.DispatchMessageA(byref(msg))
        # 循环结束要释放资源
        del eci
        self.player.close()
        del self.player
    def handle(self, eci):
        # 处理一次合成任务
        try:
            text, callback, params = self.queue.get(True, 0.01)
        except _queue.Empty:return
        # 设置临时合成参数
        if 'voice' in params.keys():
            voice = params['voice']
        else:
            voice = self.getVoice()
        try:
            eci.copyVoice(int(voice), 0)
        except:pass
        if 'pitch' in params.keys():
            eci.setVoiceParam(vpPitchBaseline, params['pitch'])
        else:
            eci.setVoiceParam(vpPitchBaseline, self.getPitch())
        if 'rate' in params.keys():
            speed = int(params['rate'])
        else:
            speed = self.getSpeed()
        eci.setVoiceParam(vpSpeed, int(self.getSpeedIncrease() * speed))
        if 'volume' in params.keys():
            eci.setVoiceParam(vpVolume, params['volume'])
        else:
            eci.setVoiceParam(vpVolume, self.getVolume())
        if 'tempo' in params.keys():
            self.player.setTempo(float(params['tempo']))
        else:
            self.player.setTempo(self.getTempo())
        # 合成过程
        self.player.play()
        eci.addText(text)
        eci.synthesize()
        eci.synchronize()
        if self.isStopped():return
        self.player.flush()
        if self.isStopped():return
        callback()
    def callback(self, msg, param, data):
        if self.isStopped(): # 如果已经被用户停止就直接放弃当前合成
            return returnDataAbort
        if msg == msgWaveformBuffer: # 把数据写入播放器
            self.player.write(string_at(self.buffer, param * 2))
        return returnDataProcessed
    def __init__(self):
        # 初始化
        self.lock = threading.RLock()
        self.setTempo(1.0)
        self.setEffect(0)
        self.setPitch(70)
        self.setSpeed(50)
        self.setSpeedIncrease(1)
        self.setVolume(100)
        self.setRdn(0)
        self.setVoice('1')
        self.queue = queue.Queue()
        # 启动线程
        self.thread = threading.Thread(target = self.run)
        self.thread.start()
    def __del__(self):
        # 释放资源
        if not hasattr(self, 'thread'):return
        self.terminate()
    def terminate(self):
        # 释放资源
        self.stop()
        user32.PostThreadMessageA(self.thread.ident, MSG_QUIT, 0, 0)
        if hasattr(self, 'thread'):
            del self.thread
        if hasattr(self, 'queue'):
            del self.queue
    def speak(self, text, callback, **params):
        # 把文本放入线程队列
        self.queue.put((text, callback, params,))
        user32.PostThreadMessageA(self.thread.ident, MSG_SPEAK, 0, 0)
    def stop(self):
        # 停止函数
        user32.PostThreadMessageA(self.thread.ident, MSG_STOP, 0, 0)
        if hasattr(self, 'player'):
            self.player.stop()
        if hasattr(self, 'queue'):
            self.queue.queue.clear()
    def pause(self, pause):
        # 暂停函数
        if hasattr(self, 'player'):
            self.player.pause(pause)
    def isStopped(self):
        # 停止函数
        if hasattr(self, 'player'):
            return self.player.isStopped()
    def setVoice(self, voice):
        # 设置语音
        with self.lock:
            self.voice = voice
    def getVoice(self):
        # 获取语音
        with self.lock:
            return self.voice
    def setEffect(self, effect):
        # 设置效果
        with self.lock:
            self.effect = int(effect)
    def getEffect(self):
        # 获取效果
        with self.lock:
            return self.effect
    def getEffects(self):
        # 获取所有效果
        return {0: '默认'}.items()
    def setSpeedIncrease(self, value):
        # 设置语速增强
        with self.lock:
            self.speedIncrease = float(value)
    def getSpeedIncrease(self):
        # 获取语速增强
        with self.lock:
            return self.speedIncrease
    def getSpeedIncreases(self):
        # 获取所有语速增强
        values = {
          1: '默认',
        }
        return values.items()
    def setSpeed(self, speed):
        # 设置语速
        with self.lock:
            self.speed = int(speed)
    def getSpeed(self):
        # 获取语速
        with self.lock:
            return int(self.speed)
    def setPitch(self, pitch):
        # 设置音高
        with self.lock:
            self.pitch = int(pitch)
    def getPitch(self):
        # 获取音高
        with self.lock:
            return self.pitch
    def setVolume(self, volume):
        # 设置音量
        with self.lock:
            self.volume = int(volume)
    def getVolume(self):
        # 获取音量
        with self.lock:
            return self.volume
    def setRdn(self, rdn):
        # 设置数字读法
        with self.lock:
            self.rdn = int(rdn)
    def getRdn(self):
        # 获取数字读法
        with self.lock:
            return self.rdn
    def getRdns(self):
        # 获取所有数字读法
        return {0: '默认'}.items()
    def getTempo(self):
        # 获取播放倍速
        with self.lock:
            return self.tempo
    def setTempo(self, tempo):
        # 设置播放倍速
        with self.lock:
            self.tempo = float(tempo)